﻿#include "netBase.h"
#include "netTool.h"

#include <functional>
#include <chrono>

	

#ifdef _WIN32
#pragma comment(lib,"ws2_32.lib")
#else
#include <memory.h>
#include <sys/select.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <unistd.h>
#include <fcntl.h>


#endif




netTcpServer::netTcpServer(cmdWorker * parser):
	serSockFD(INVALID_SOCKET), cliSockFD(INVALID_SOCKET), bufferUsed(0),
	worker(parser)
{
	 memset(recvBuf,0,sizeof(recvBuf));
}

netTcpServer::~netTcpServer()
{
	
	netServerStop();
}

int netTcpServer::netServerInit(int port)
{
	if (serSockFD == INVALID_SOCKET) {
#ifdef _WIN32
		WSADATA wsaData;
		if (SOCKET_ERROR == WSAStartup(MAKEWORD(2, 2), &wsaData)) {
			std::cout << " WSAStartup error \n";
			return -1;
		}
		if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wHighVersion) != 2) {
			std::cout << "socket version is not support\n";
			WSACleanup();
		}
#endif

		serSockFD = socket(AF_INET, SOCK_STREAM, 0);
		if (serSockFD == INVALID_SOCKET) {
			std::cout << " socket error port " << port << std::endl;
			serSockFD = INVALID_SOCKET;
			return -1;
		}

		struct sockaddr_in sockCfg = {};
		
		inet_pton(AF_INET, INADDR_ANY, &sockCfg.sin_addr.s_addr);
		//sockCfg.sin_addr.S_un.S_addr = inet_addr(ADDR_ANY);
		sockCfg.sin_port = htons(port);
		sockCfg.sin_family = AF_INET;

		int ret = ::bind(serSockFD, (sockaddr*)&sockCfg, sizeof(sockCfg));
		if (ret < 0) {
			std::cout << "error bind " << ret << std::endl;
			closesocket(serSockFD);
			serSockFD = INVALID_SOCKET;
			return -1;
		}

		ret = listen(serSockFD, 1);
		if (ret < 0) {
			std::cout << "error listen " << ret << std::endl;
			closesocket(serSockFD);
			serSockFD = INVALID_SOCKET;
			return -1;
		}

		thrHelper.reset(new ThreadHelper(std::bind(static_cast<int(netTcpServer::*)()>(&netTcpServer::sockSelect), this),false));
//		auto cb = std::bind(static_cast<int(netTcpServer::*)(int, char*, int)>(&netTcpServer::sockSelect), this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
//		SelectHelper::INS().FD_SELECT(serSockFD, cb);
	}
	else {
		std::cout << "error tcp sever socket is inited";
	}
	return 0;
}

int netTcpServer::netServerStop()
{
    if(thrHelper.get())
        thrHelper->thrstop();

    if (cliSockFD != INVALID_SOCKET) {
        closesocket(cliSockFD);
        cliSockFD = INVALID_SOCKET;
    }

    if (serSockFD != INVALID_SOCKET) {
        closesocket(serSockFD);
        serSockFD = INVALID_SOCKET;
    }
	return 0;
}

int netTcpServer::netServerSend(const uint8_t * data, int length)
{
	if (data == nullptr || length <= 0 || cliSockFD == INVALID_SOCKET) {
		std::cout << "netServerSend error\n";
		return -1;
	}

    std::string  sendStr = worker->protocalSerial((const char *)data,length);
	
	std::lock_guard<std::mutex> lock(mutexSend);
    return ::send(cliSockFD,sendStr.data(),sendStr.size(),0);
}

int netTcpServer::sockSelect()
{
	fd_set fdSet;
	FD_ZERO(&fdSet);
	
	FD_SET(serSockFD, &fdSet);

	if (cliSockFD != INVALID_SOCKET) {
		FD_SET(cliSockFD, &fdSet);
	}

    struct timeval timeout = { 0,500*1000};

	int ret = ::select(0, &fdSet, nullptr, nullptr, &timeout);
	if (ret == 0) {
		
	}
	else if (ret > 0) {

		if (FD_ISSET(cliSockFD, &fdSet)) {
            memset(recvBuf + bufferUsed,0,sizeof(recvBuf) - bufferUsed);
			ret = ::recv(cliSockFD, (char*)(recvBuf + bufferUsed), sizeof(recvBuf) - bufferUsed, 0);
			if (ret <= 0) {
				closesocket(cliSockFD);
				cliSockFD = INVALID_SOCKET;
				bufferUsed = 0;
				
			}
			else {
                std::string repStr;
				ret += bufferUsed;
                int used = worker->protocalParse(cliSockFD,(char*)recvBuf, ret,repStr);
                std::cout << "net server recved "<< ret << " used "<< used << std::endl;
				if (ret > used) {
					memmove(recvBuf, recvBuf + used, ret - used);
					std::cout << "parse recv,free " << ret - used << std::endl;
				}

                if(repStr.size() > 0){
                    netServerSend((uint8_t*)repStr.data(),repStr.size());
                }

				bufferUsed = ret - used;
			}
		}


		// 有新连接
		if (FD_ISSET(serSockFD, &fdSet)) {
			struct sockaddr_in sockCli = {};
			socklen_t sockCliSize = sizeof(sockCli);
			SOCKET tmpCliFD = ::accept(serSockFD, (sockaddr*)&sockCli, &sockCliSize);
			if (tmpCliFD == INVALID_SOCKET) {
				std::cout << "error accept new connect " << ret << std::endl;
                return 0;
			}

			if (cliSockFD != INVALID_SOCKET) {
				closesocket(cliSockFD);
			}
			cliSockFD = tmpCliFD;
		}
	}
	else {
		std::cout << "error select error " << ret;
        return -1;
	}


	return 0;
}



int netTcpServer::sockSelect(int fd,char * data, int length)
{
	// 新连接
	if (fd == serSockFD) {
		struct sockaddr_in sockCli = {};
		socklen_t sockCliSize = sizeof(sockCli);
		SOCKET tmpCliFD = ::accept(serSockFD, (sockaddr*)&sockCli, &sockCliSize);
		if (tmpCliFD == INVALID_SOCKET) {
			std::cout << "error accept new connect " << tmpCliFD << std::endl;
			return 0;
		}

		if (cliSockFD != INVALID_SOCKET) {
			closesocket(cliSockFD);
		}
		cliSockFD = tmpCliFD;
	}
	else {
		// 客户端
		int ret = ::recv(cliSockFD, (char*)(recvBuf + bufferUsed), sizeof(recvBuf) - bufferUsed, 0);
		if (ret <= 0) {
			closesocket(cliSockFD);
			cliSockFD = INVALID_SOCKET;
			bufferUsed = 0;

		}
		else {
			std::string repStr;
			ret += bufferUsed;
			int used = worker->protocalParse(cliSockFD,(char*)recvBuf, ret, repStr);
			lcout << "net server recved " << ret << " used " << used << std::endl;
			if (ret > used) {
				memmove(recvBuf, recvBuf + used, ret - used);
				lcout << "parse recv,free " << ret - used << std::endl;
			}

			if (repStr.size() > 0) {
				netServerSend((uint8_t*)repStr.data(), repStr.size());
			}

			bufferUsed = ret - used;
		}
	}
	return 0;
}










netTcpClient::netTcpClient(cmdWorker * parser):
    cliSockFD(INVALID_SOCKET),bufferUsed(0), worker(parser)
{

}



netTcpClient::~netTcpClient()
{
	netClientClose();
}



int netTcpClient::netClientConnect(const char * ip, int port, int timeoutSec)
{
	if (cliSockFD == INVALID_SOCKET) {
#ifdef _WIN32
		WSADATA wsaData;
		if (SOCKET_ERROR == WSAStartup(MAKEWORD(2, 2), &wsaData)) {
			std::cout << " WSAStartup error \n";
			return -1;
		}
		if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wHighVersion) != 2) {
			std::cout << "套接字库版本号不符\n";
			WSACleanup();
		}

#endif
		cliSockFD = socket(AF_INET, SOCK_STREAM, 0);
		if (cliSockFD == INVALID_SOCKET) {
			std::cout << " socket error port " << port << std::endl;
			cliSockFD = INVALID_SOCKET;
			return -1;
		}

		struct sockaddr_in sockCfg = {};
		inet_pton(AF_INET, ip, &sockCfg.sin_addr.s_addr);
		//sockCfg.sin_addr.S_un.S_addr = inet_addr(ADDR_ANY);
		sockCfg.sin_port = htons(port);
		sockCfg.sin_family = AF_INET;

		int ret = connectTimeOut(cliSockFD, (sockaddr*)&sockCfg, sizeof(sockCfg), timeoutSec);
		if (ret < 0) {
			std::cout << "connectTimeOut error\n";

			closesocket(cliSockFD);
			cliSockFD = INVALID_SOCKET;
			return -1;
		}

//		thrHelper.reset(new ThreadHelper(std::bind(&netTcpClient::sockSelect, this), false));
		auto cb = std::bind(static_cast<int(netTcpClient::*)(int, char*, int)>(&netTcpClient::sockSelect), this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
		SelectHelper::INS().FD_SELECT(cliSockFD, cb);
	}
	else {
		std::cout << "error tcp sever socket is inited";
	}
	return 0;
}

int netTcpClient::netClientClose()
{
	if (thrHelper.get()) {
		thrHelper->thrstop();
	}

    if (cliSockFD != INVALID_SOCKET) {
        closesocket(cliSockFD);
        cliSockFD = INVALID_SOCKET;
    }

	return 0;
}

int netTcpClient::netClientRequire(const char * data, int length)
{
	if (data == nullptr || length <= 0 || cliSockFD == INVALID_SOCKET) {
		std::cout << "netServerSend error\n";
		return -1;
	}

	std::string cmd = worker->protocalSerial(data, length);

	std::lock_guard<std::mutex> lock(mutexSend);
	return ::send(cliSockFD, cmd.data(), cmd.size(), 0);

}

int netTcpClient::sockSelect()
{
	if (cliSockFD == INVALID_SOCKET) {
		std::this_thread::sleep_for(std::chrono::milliseconds(200));
		return 0;
	}

	fd_set fdSet;
	FD_ZERO(&fdSet);
	FD_SET(cliSockFD, &fdSet);
	

	struct timeval timeout = { 2,0 };

	int ret = ::select(0, &fdSet, nullptr, nullptr, &timeout);
	if (ret == 0) {
        return 0;
	}
	else if (ret > 0) {

		if (FD_ISSET(cliSockFD, &fdSet)) {
            memset(recvBuf + bufferUsed,0,sizeof(recvBuf) - bufferUsed);
			ret = ::recv(cliSockFD, (char*)(recvBuf + bufferUsed), sizeof(recvBuf) - bufferUsed, 0);
			if (ret <= 0) {
				closesocket(cliSockFD);
				cliSockFD = INVALID_SOCKET;
				bufferUsed = 0;

			}
			else {
                std::string repStr; // 待定
				ret += bufferUsed;
                int used = worker->protocalParse(cliSockFD,(char*)recvBuf, ret,repStr);
				if (ret > used) {
					memmove(recvBuf, recvBuf + used, ret - used);
					std::cout << "parse recv,free " << ret - used << std::endl;
				}

                if(repStr.size() > 0){
                    netClientRequire(repStr.data(),repStr.size());
                }

				bufferUsed = ret - used;
			}
		}
	}
	else {
        std::cout << "select error " << ret;
        return -1;
	}

	return 0;
}

int netTcpClient::sockSelect(int fd, char * data, int length)
{
	if (length > 0) {

	}
	else {
		lcout << "error client fd is error,close socket\n";
	}
	return 0;
}




#ifdef _WIN32
int netTcpClient::connectTimeOut(SOCKET sockfd, const sockaddr* addr, int addrlen, int timeoutSec)
{
	// 设置socket为非阻塞模式
	u_long mode = 1;
	if (ioctlsocket(sockfd, FIONBIO, &mode) != 0) {
		int error = WSAGetLastError();
		printf("ioctlsocket error: %d\n", error);
		return error;
	}

	// 开始连接
	if (connect(sockfd, addr, addrlen) == 0) {
		// 连接成功
		mode = 0;
		if (ioctlsocket(sockfd, FIONBIO, &mode) != 0) {
			int error = WSAGetLastError();
			printf("ioctlsocket error: %d\n", error);
			return error;
		}
		return 0;
	}
	else if (WSAGetLastError() != WSAEWOULDBLOCK) {
		// 连接错误
		int error = WSAGetLastError();
		printf("connect error: %d\n", error);
		return error;
	}

	// 创建事件对象
	HANDLE event = WSACreateEvent();
	if (event == NULL) {
		int error = WSAGetLastError();
		printf("WSACreateEvent error: %d\n", error);
		return error;
	}

	// 将事件对象与socket关联
	if (WSAEventSelect(sockfd, event, FD_CONNECT) != 0) {
		int error = WSAGetLastError();
		printf("WSAEventSelect error: %d\n", error);
		WSACloseEvent(event);
		return error;
	}

	// 使用WSAWaitForMultipleEvents函数等待连接完成或超时
	DWORD result = WSAWaitForMultipleEvents(1, &event, FALSE, timeoutSec * 1000, FALSE);
	if (result == WSA_WAIT_TIMEOUT) {
		// 连接超时
		closesocket(sockfd);
		WSACloseEvent(event);
		printf("connect timeout\n");
		return -1;
	}
	else if (result == WSA_WAIT_FAILED) {
		// 等待事件失败
		int error = WSAGetLastError();
		printf("WSAWaitForMultipleEvents error: %d\n", error);
		closesocket(sockfd);
		WSACloseEvent(event);
		return error;
	}

	// 检查socket连接状态
	WSANETWORKEVENTS networkEvents;
	if (WSAEnumNetworkEvents(sockfd, event, &networkEvents) != 0) {
		int error = WSAGetLastError();
		printf("WSAEnumNetworkEvents error: %d\n", error);
		closesocket(sockfd);
		WSACloseEvent(event);
		return error;
	}

	if ((networkEvents.lNetworkEvents & FD_CONNECT) == 0 || networkEvents.iErrorCode[FD_CONNECT_BIT] != 0) {
		// 连接错误
		int error = WSAGetLastError();
		printf("connect error: %d\n", error);
		closesocket(sockfd);
		WSACloseEvent(event);
		return error;
	}

	WSAEventSelect(sockfd, event, 0);

	// 设置socket为阻塞模式
	mode = 0;
	if (ioctlsocket(sockfd, FIONBIO, &mode) != 0) {
		int error = WSAGetLastError();
		printf("ioctlsocket error: %d\n", error);
		return error;
	}
	
	WSACloseEvent(event);
	return 0;
}
#else
int netTcpClient::connectTimeOut(SOCKET sockfd, const sockaddr* addr, int addrlen, int timeoutSec){
	 // 设置套接字为非阻塞模式
    int flags = fcntl(sockfd, F_GETFL, 0);
    fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);

    // 连接远程主机
    int ret = connect(sockfd, addr, addrlen);
    if (ret == 0) {
        // 连接成功，恢复套接字的阻塞模式
        fcntl(sockfd, F_SETFL, flags);
        return 0;
    } else if (errno != EINPROGRESS) {
        // 连接失败，不是正在进行中的连接，恢复套接字的阻塞模式
        fcntl(sockfd, F_SETFL, flags);
        return -1;
    }

    // 等待连接成功或超时
    fd_set writefds;
    FD_ZERO(&writefds);
    FD_SET(sockfd, &writefds);

    struct timeval tv;
    tv.tv_sec = timeoutSec;
    tv.tv_usec = 0;

    ret = select(sockfd + 1, NULL, &writefds, NULL, &tv);
    if (ret <= 0) {
        // 连接超时或出错，关闭套接字
        close(sockfd);
        return -1;
    }

    // 获取套接字的错误状态
    int error = 0;
    socklen_t len = sizeof(error);
    ret = getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len);
    if (ret < 0 || error != 0) {
        // 连接出错，关闭套接字
        close(sockfd);
        return -1;
    }

    // 连接成功，恢复套接字的阻塞模式
    fcntl(sockfd, F_SETFL, flags);
    return 0;
}
#endif












netUdp::netUdp(cmdWorker * parser):
	localSock(INVALID_SOCKET),worker(parser)
{
	memset(recvBuf, 0, sizeof(recvBuf));
}

netUdp::~netUdp()
{
	netclose();
}

int netUdp::netUdpInit(const char * ip, int port)
{
#ifdef _WIN32
	// 初始化Winsock库
	WSADATA wsaData;
	if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
		std::cerr << "Failed to initialize Winsock" << std::endl;
		return -1;
	}
#endif

	// 创建套接字
	localSock = socket(AF_INET, SOCK_DGRAM, 0);
	if (localSock == INVALID_SOCKET) {
		std::cerr << "Failed to create socket" << std::endl;
		WSACleanup();
		return -1;
	}

	//setsockopt(localSock, IPPROTO_IP, IP_ADD_MEMBERSHIP,)
	
	// 绑定套接字到IP和端口
	sockaddr_in serverAddr{};
	serverAddr.sin_family = AF_INET;
	serverAddr.sin_port = htons(port);
	if (ip == nullptr)
	{
		serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
	}
	else
	{
		inet_pton(AF_INET, ip, &serverAddr.sin_addr.s_addr);
	}
	if (::bind(localSock, (sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
		std::cerr << "Failed to bind socket" << std::endl;
		closesocket(localSock);
		WSACleanup();
		return -1;
	}

	// ip_mreq mreq{};
	// inet_pton(AF_INET, SSDP_ADDR, &mreq.imr_multiaddr.s_addr);
	// mreq.imr_interface.s_addr = htonl(INADDR_ANY);

	// if (setsockopt(localSock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&mreq, sizeof(mreq)) == SOCKET_ERROR) {
	// 	std::cerr << "Failed to set socket options." << std::endl;
	// 	closesocket(localSock);
	// 	return -1;
	// }

	auto cb = std::bind(static_cast<int(netUdp::*)(int, char*, int)>(&netUdp::sockSelect), this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
	SelectHelper::INS().FD_SELECT(localSock, cb);

	return 0;
}

int netUdp::netUdpSend(const char * data, int length,const char* ip,int port)
{
	if (data == nullptr || length <= 0 || localSock == INVALID_SOCKET) {
		std::cout << "netUdpSend error\n";
		return -1;
	}

	std::string cmd = worker->protocalSerial(data, length);


	sockaddr_in serverAddr{};
	serverAddr.sin_family = AF_INET;
	serverAddr.sin_port = htons(port);
	inet_pton(AF_INET, ip, &serverAddr.sin_addr.s_addr);

	std::lock_guard<std::mutex> lock(mutexSend);
	return ::sendto(localSock, cmd.data(), cmd.size(), 0, (struct sockaddr*)&serverAddr, sizeof(serverAddr));
}

int netUdp::netclose()
{
	if (localSock != INVALID_SOCKET)
	{
		SelectHelper::INS().FD_CANCEL(localSock);
		closesocket(localSock);
		localSock = INVALID_SOCKET;
	}
	
	return 0;
}

int netUdp::sockSelect()
{
    return 0;
}

int netUdp::sockSelect(int fd, char *data, int length)
{
	if (length < 0) {
		SelectHelper::INS().FD_CANCEL(fd);

		closesocket(localSock);
		localSock = INVALID_SOCKET;
		return 0;
	}

	std::string repStr;
	worker->protocalParse(fd,data, length, repStr);
	/*if (repStr.empty()) {
		netUdpSend(repStr.data(), repStr.size());
	}*/

	return 0;
}
